/*
 * Copyright (c) 2013-2018 上海汇数数据. All rights reserved.
 * @(#) ChinaID.java 2018-08-05 23:24
 */

package cn.jh.common.core.id;

import cn.jh.common.core.domain.Gender;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;
import org.joda.time.LocalDate;

import java.io.Serializable;


/**
 * 表示中国公民身份证信息的一个抽象类。
 * <pre>中国大陆身份证格式：
 * 前1、2位数字表示：所在省份的代码；
 * 第3、4位数字表示：所在城市的代码；
 * 第5、6位数字表示：所在区县的代码；
 * 第7~14位数字表示：出生年、月、日；
 * 第15、16位数字表示：所在地的派出所的代码；
 * 第17位数字表示性别：奇数表示男性，偶数表示女性；
 * 第18位字符是校检码：根据前17位数字根据特有的算法得出的值，范围：{@code 0~9, X}
 *
 * 中国台湾身份证格式：
 * "[A-Z][1-2][0-9]{8}"  一个大写英文字母+9个数字，最后一位是校验码
 * 第1个英文字符表示：初次登记的户籍地
 * 第2个数字表示：1-男性，2-女性
 * 第3~9位是一串数字表示：
 * </pre>
 * NOTE: 参见中国大陆、台湾、香港身份证格式说明：
 * <a href="https://zh.wikipedia.org/wiki/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E5%85%AC%E6%B0%91%E8%BA%AB%E4%BB%BD%E5%8F%B7%E7%A0%81">中华人民共和国公民身份号码</a>
 * <a href="https://zh.wikipedia.org/wiki/%E4%B8%AD%E8%8F%AF%E6%B0%91%E5%9C%8B%E5%9C%8B%E6%B0%91%E8%BA%AB%E5%88%86%E8%AD%89">中華民國國民身分證</a>
 * <a href="https://zh.wikipedia.org/wiki/%E9%A6%99%E6%B8%AF%E8%BA%AB%E4%BB%BD%E8%AD%89">香港身份證</a>
 *
 * @author Fuchun
 * @since 1.0
 */
public abstract class ChinaID implements ID, Serializable {

    private static final long serialVersionUID = 1L;

    @Contract("null -> false")
    public static boolean validId(String id) {
        if (id == null || id.length() == 0) return false;
        switch (id.length()) {
            case 10:
                if (!id.contains("(")) {
                    return TWChinaID.validId(id);
                }
                return HKChinaID.validId(id);
            case 11:
                return HKChinaID.validId(id);
            case 18:
                return MLChinaID.validId(id);
            default:
                return false;
        }
    }

    @Contract("null -> null")
    public static ChinaID parse(String id) {
        if (id == null || id.length() == 0) return null;
        switch (id.length()) {
            case 10: // TW or HK
                if (!id.contains("(")) { // TW
                    return TWChinaID.parse(id);
                }
                return HKChinaID.parse(id);
            case 11: // HK
                return HKChinaID.parse(id);
            case 18:
                return MLChinaID.parse(id);
            default:
                return new ErrorChinaID(id);
        }
    }

    /**
     * 身份证号码中识别的所在地区码。
     * <pre>
     * 中国大陆身份证：省（直辖市）编码；
     * 中国台湾身份证：固定值为："71"
     * 中国香港身份证：固定值为："81"
     * 中国澳门身份证：固定值为："82"
     * </pre>
     */
    public abstract String getStateCode();

    /**
     * 身份证号码中识别的所在城市码。
     * <pre>
     * 中国大陆身份证：城市编码（身份证号码第3~第6位的4位数字编码）；
     * 中国台湾身份证：{@code [A-Z]} 身份证号码首位
     * 中国香港身份证：{@code [A-Z]} 身份证号码首位
     * 中国澳门身份证：固定值为 "" (空字符串)
     * </pre>
     */
    public abstract String getAreaCode();

    /**
     * 身份证号码中识别的性别。
     * <pre>
     * 中国大陆身份证：倒数第2位奇数为男性，偶数为女性；
     * 中国台湾身份证：顺数第2位1为男性，2为女性；
     * 中国香港身份证：无法识别，固定值 {@link Gender#UNKNOWN}；
     * 中国澳门身份证：无法识别，固定值 {@link Gender#UNKNOWN}；
     * </pre>
     *
     * @return 返回身份证号码中识别的性别。
     */
    public abstract Gender getGender();

    /**
     * 身份证号码中识别的生日日期。
     * <pre>
     * 中国大陆身份证：根据第7~14位出生年月日计算；
     * 中国台湾身份证：无法识别，固定值：null；
     * 中国香港身份证：无法识别，固定值：null；
     * 中国澳门身份证：无法识别，固定值：null；
     * </pre>
     *
     * @return 返回身份证号码中识别的生日日期。
     */
    @Nullable
    public abstract LocalDate getBirthday();

    /**
     * 身份证号码中识别并计算出的年龄。
     * <pre>
     * 中国大陆身份证：根据第7~14位出生年月日计算；
     * 中国台湾身份证：无法识别，固定值：-1；
     * 中国香港身份证：无法识别，固定值：-1；
     * 中国澳门身份证：无法识别，固定值：-1；
     * </pre>
     *
     * @return 返回身份证号码中识别并计算出的年龄。
     */
    public abstract int getAge();
}
